package com.ljx.recruitment.security.util;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import com.ljx.recruitment.common.constant.CacheConstants;
import com.ljx.recruitment.common.exception.ApiException;
import com.ljx.recruitment.common.util.RedisUtil;
import com.ljx.recruitment.security.common.UserContext;
import com.ljx.recruitment.user.cache.UserCache;
import com.ljx.recruitment.user.domain.dto.UserDto;
import com.ljx.recruitment.user.domain.entity.*;
import com.ljx.recruitment.user.domain.vo.resp.UserResp;
import com.ljx.recruitment.user.enums.CommonRoleEnum;
import com.ljx.recruitment.user.service.*;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @Author: LiJunXi
 * @Description:
 * @Date: 2024-10-02  00:14
 */
public class UserUtil {

    public static void setUserCache(UserResp userResp) {
        RedisUtil.set(CacheConstants.getKey(CacheConstants.USER_INFO, userResp.getId()),
                JSONUtil.toJsonStr(userResp), CacheConstants.USER_INFO_EXPIRE_TIME, TimeUnit.HOURS);
    }

    public static void deleteUserCache(Long userId) {
        RedisUtil.del(CacheConstants.getKey(CacheConstants.USER_INFO, userId));
    }

    public static UserResp getUserCache(Long userId) {
        return JSONUtil.toBean(RedisUtil.get(CacheConstants.getKey(CacheConstants.USER_INFO, userId)), UserResp.class);
    }

    public static UserDto getUserInfo(){
        return UserContext.getUser();
    }

    public static Long getUserId(){
        return getUserInfo().getId();
    }

    private static final String SECRET = "eyJqdGkiOiI0MDQiLCJzdWIiOiLpgqLnq4vosbkiL";

    public static String createToken(Long userId, Long tokenId) {
        Map<String, Object> map = new HashMap<>();
        map.put("userId", userId);
        map.put("tokenId", tokenId);
        // 设置时间，用于自动刷新有效期
        long nowTime = System.currentTimeMillis();
        map.put("loginTime", nowTime);
        map.put("expireTime", nowTime + CacheConstants.LOGIN_TOKEN_KEY_EXPIRE_TIME_TIMESTAMP);
        return Jwts.builder()
                .signWith(SignatureAlgorithm.HS512, SECRET)
                .setClaims(map)
                .compact();
    }

    public static void setTokenCache(UserDto userDto, Long tokenId) {
        RedisUtil.set(CacheConstants.getKey(CacheConstants.LOGIN_TOKEN_KEY, tokenId), JSONUtil.toJsonStr(userDto),
                CacheConstants.LOGIN_TOKEN_KEY_EXPIRE_TIME, TimeUnit.HOURS);
    }

    public static UserDto getTokenCache(Long tokenId) {
        return JSONUtil.toBean(RedisUtil.get(CacheConstants.getKey(CacheConstants.LOGIN_TOKEN_KEY, tokenId)), UserDto.class);
    }

    public static UserDto parseTokenToUser(String token) {
        Claims claims = getClaims(token);
        Long tokenId = Long.parseLong(claims.get("tokenId").toString());
        String userStr = RedisUtil.get(CacheConstants.getKey(CacheConstants.LOGIN_TOKEN_KEY, tokenId));
        if (StrUtil.isEmpty(userStr)) {
            throw new ApiException("身份过期，请重新登录");
        }
        UserDto userDto = JSONUtil.toBean(userStr, UserDto.class);
        refreshToken(tokenId, claims, userDto);
        return userDto;
    }

    private static void refreshToken(Long tokenId, Claims claims, UserDto userDto) {
        Long nowTime = System.currentTimeMillis();
        Long expireTime = Long.parseLong(claims.get("expireTime").toString());
        if (expireTime + CacheConstants.LOGIN_TOKEN_KEY_VALID_TIME_TIMESTAMP <= nowTime) {
            setTokenCache(userDto, tokenId);
        }
    }

    public static Claims getClaims(String token) {
        Claims claims = Jwts.parser()
                .setSigningKey(SECRET)
                .parseClaimsJws(token)
                .getBody();
        return claims;
    }

    public static List<Role> tryToGetUserRole(Long userId) {
        RoleService roleService = SpringUtil.getBean(RoleService.class);
        List<Long> roleIds = roleService.getUserRoleIdByUserId(userId);
        if (roleIds.isEmpty()){
            return new ArrayList<>();
        }
        return roleService.getRoleByIds(roleIds);
    }

    public static List<Permission> tryToGetUserPermission(Long userId) {
        PermissionService permissionService = SpringUtil.getBean(PermissionService.class);
        List<Long> roles = tryToGetUserRole(userId).stream().map(Role::getId).collect(Collectors.toList());
        if (roles.isEmpty()){
            return new ArrayList<>();
        }
        List<Long> permissionByRoleIds = permissionService.getPermissionIdByRoleIds(roles);
        return permissionService.getPermissionByIds(permissionByRoleIds);
    }

    public static List<Menu> tryToGetUserMenu(Long userId) {
        MenuService menuService = SpringUtil.getBean(MenuService.class);
        List<Long> roles = tryToGetUserRole(userId).stream().map(Role::getId).collect(Collectors.toList());
        if (roles.isEmpty()){
            return new ArrayList<>();
        }
        List<Long> menuIds = menuService.getMenuIdByRoleIds(roles);
        return menuService.getMenuByIds(menuIds);
    }


    public static Long tryToGetUserTenantId(Long userId){
        UserCache userCache = SpringUtil.getBean(UserCache.class);
        User user = userCache.get(userId);
        return user.getTenantId();
    }

    public static Long tryToGetTenantId(){
        Long tenantId = UserContext.getTenantId();
        if (Objects.isNull(tenantId)){
            throw new ApiException("租户参数不能为空");
        }
        return tenantId;
    }

    public static boolean checkIsPlatformAdmin() {
        UserDto userInfo = UserUtil.getUserInfo();
        if (Objects.isNull(userInfo)) {
            return false;
        }
        List<Role> roles = userInfo.getRoles();
        if (CollectionUtil.isEmpty(roles)){
            return false;
        }
        return roles.stream().anyMatch(item -> item.getName().equals(CommonRoleEnum.getAdminCode(CommonRoleEnum.PLATFORM.getKey())));
    }

    public static Boolean checkIsTenantAdmin() {
        List<Role> roles = UserUtil.getUserInfo().getRoles();
        if (CollectionUtil.isEmpty(roles)){
            return false;
        }
        Long tenantId = UserUtil.tryToGetTenantId();
        TenantService tenantService = SpringUtil.getBean(TenantService.class);
        Tenant tenant = tenantService.getById(tenantId);
        return roles.stream().anyMatch(item -> item.getName().equals(CommonRoleEnum.getAdminCode(tenant.getCode())));
    }

    public static Boolean checkIsStaff() {
        List<Role> roles = UserUtil.getUserInfo().getRoles();
        if (CollectionUtil.isEmpty(roles)){
            return false;
        }
        Long tenantId = UserUtil.tryToGetTenantId();
        TenantService tenantService = SpringUtil.getBean(TenantService.class);
        Tenant tenant = tenantService.getById(tenantId);
        return roles.stream().anyMatch(item -> item.getName().equals(CommonRoleEnum.getStaffCode(tenant.getCode())));
    }

    public static Boolean checkIsUser() {
        List<Role> roles = UserUtil.getUserInfo().getRoles();
        if (CollectionUtil.isEmpty(roles)){
            return false;
        }
        Long tenantId = UserUtil.tryToGetTenantId();
        TenantService tenantService = SpringUtil.getBean(TenantService.class);
        Tenant tenant = tenantService.getById(tenantId);
        return roles.stream().anyMatch(item -> item.getName().equals(CommonRoleEnum.getUserCode(tenant.getCode())));
    }

    public static Boolean checkIsHr() {
        List<Role> roles = UserUtil.getUserInfo().getRoles();
        if (CollectionUtil.isEmpty(roles)){
            return false;
        }
        Long tenantId = UserUtil.tryToGetTenantId();
        TenantService tenantService = SpringUtil.getBean(TenantService.class);
        Tenant tenant = tenantService.getById(tenantId);
        return roles.stream().anyMatch(item -> item.getName().equals(CommonRoleEnum.getHrCode(tenant.getCode())));
    }

    public static void checkIsSameTenant() {
        UserCache userCache = SpringUtil.getBean(UserCache.class);
        Long tenantId = UserUtil.tryToGetTenantId();
        User user = userCache.get(UserUtil.getUserId());
        if (Objects.isNull(tenantId) || Objects.isNull(user) || !user.getTenantId().equals(tenantId)){
            throw new ApiException("权限不足");
        }
    }
    public static Boolean checkIsNotLogin() {
        return Objects.isNull(getUserInfo());
    }
    public static Boolean checkIsAnonymous() {
        if (Objects.isNull(getUserInfo())) {
            return false;
        }
        String code = CommonRoleEnum.getAnonymousCode(CommonRoleEnum.PLATFORM.getKey());
        for (Role role : getUserInfo().getRoles()) {
            if (role.getName().equals(code)) {
                return true;
            }
        }
        return false;
    }
}
